Skip to content

gh#346: WTF-8 dict-key and type-lookup residual coverage - #1177

Merged
youknowone merged 3 commits into
mainfrom
rtyper-legacy
Aug 12, 2026
Merged

gh#346: WTF-8 dict-key and type-lookup residual coverage#1177
youknowone merged 3 commits into
mainfrom
rtyper-legacy

Conversation

@youknowone

@youknowone youknowone commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Two gh#346 slices growing two-phase (annotate→rtype) rtyper coverage so more JIT-traced graphs lift through the CodeWriter path instead of the legacy walker.

3ea880f2875 — generic Into<Wtf8Buf> message alias

Widens the String-only Into<Wtf8Buf> message-conversion aliases to tyref_is_string_value, so PyError::new's impl Into<Wtf8Buf> clause folds to its operand. phaseA prepass fallback 1709 → 1381 (−328).

5735933d692 — WTF-8 dict-key split + type-lookup projection

  • Three WTF-8 dict adapters (w_dict_getitem_wtf8, w_dict_getitem_wtf8_checked, w_dict_setitem_wtf8) branched on key.as_str(), whose Result<&str, Utf8Error> cannot cross the residual-call boundary. Each is decomposed into a #[dont_look_inside] validity probe (wtf8_key_is_utf8), an identity-folded reinterpret (wtf8_key_as_str_unchecked, folded to its receiver by wtf8_string_identity_alias), and a #[dont_look_inside] lone-surrogate key object (wtf8_surrogate_key_str_object).
  • lookup_in_type_wtf8_uncached is marked #[dont_look_inside], restoring symmetry with its already-residual &str twin lookup_in_type_where_uncached: its .map over the opaque lookup_where_pair_wtf8_uncached's Option<(PyObjectRef, PyObjectRef)> kept a tuple-payload projection on the trace surface; it now residualises to the single-word Option<PyObjectRef>.
  • Measured effect (fresh post-#1168 ullbc A/B): +17 lifted graphs — the attribute/descriptor lookup spine (lookup, lookup_in_type_where_wtf8, is_data_descr, is_object_getattribute_descr, is_type_getattribute_descr, descr_has_delete, …) — 0 regressions. The dict-adapter decompose is a correct, separable prerequisite (0 standalone lift; its _io target cluster relocates to the next wall, Flatten::next).

bd4acf94387getattribute attribute-miss residual

object_getattr_miss — the miss / special-attribute path of getattribute, reached only after the fast descriptor and instance-dict lookups return nothing — is marked #[dont_look_inside] and registered in jit_fnaddr. Its [Option<PyObjectRef>; 2].iter().flatten() metaclass walks and array indexing are opaque to the annotator; it returns the blessed PyResult carrier, so the whole cold path residualises behind one boundary. This clears the Flatten::next prepass fallback (the next wall of the dict-routed _io/load_* cluster surfaced by the slice above); the getattr graphs relocate to their next wall rather than lifting (0 standalone lift — a prerequisite that clears the wall class, not a lift).

Gates

  • cargo test --all --no-default-features --features dynasm — 7669 passed / 0 failed.
  • check.py 3-backend bit-exact — dynasm 420/420, cranelift 419/419, wasm 414/414, cpython-suite 209 modules.

commented by Claude

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of WTF-8 strings and string-like values during dictionary lookups and updates.
    • Preserved correct behavior for dictionary keys containing surrogate characters.
    • Improved compatibility when converting or comparing supported string representations.
  • Performance

    • Streamlined common dictionary operations for valid UTF-8 keys while retaining fallback handling for non-UTF-8 content.
    • Improved runtime resolution of specialized string-key operations.

The two frontend identity gates for a generic-clause `msg.into()`
(`trait_clause_into_string_identity`, `trait_into_string_alias`) accepted
only `alloc::string::String` as the destination. The `PyError` constructor
family takes `impl Into<Wtf8Buf>`, whose `.into()` targets `Wtf8Buf`, so both
gates rejected it and the call lowered to an unregistered `["Into", "into"]`,
failing the lift of `PyError::new` / `type_error` and every graph raising
through them.

Widen both gates to `tyref_is_string_value` (`String` / `Wtf8` / `Wtf8Buf` /
`str`, all projecting to the single immutable `s_unicode0`). Remove the
now-unused `tyref_adt_name_path`.

Prepass census (b9ac697): phaseA 1709 -> 1381, phaseB 14 -> 4; 328 graphs
lift, 0 new failures. cargo test --features dynasm clean; check.py bit-exact
dynasm 420/420, cranelift 419/419, wasm 414/414.

Assisted-by: Claude
Three WTF-8 dict adapters (w_dict_getitem_wtf8, w_dict_getitem_wtf8_checked,
w_dict_setitem_wtf8) branched on `key.as_str()`, whose
`Result<&str, Utf8Error>` cannot cross the residual-call boundary.
Decompose each into a `#[dont_look_inside]` validity probe
(wtf8_key_is_utf8), an identity-folded reinterpret
(wtf8_key_as_str_unchecked, folded to its receiver by
wtf8_string_identity_alias), and a `#[dont_look_inside]` lone-surrogate
key object (wtf8_surrogate_key_str_object).

Mark lookup_in_type_wtf8_uncached `#[dont_look_inside]`, matching its
`&str` twin lookup_in_type_where_uncached: its `.map` over the opaque
lookup_where_pair_wtf8_uncached's `Option<(PyObjectRef, PyObjectRef)>`
kept a tuple-payload projection on the trace surface. It now residualises
to the single-word `Option<PyObjectRef>`.

Register the three new residual helpers in jit_fnaddr.

Assisted-by: Claude
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d85da144-8d06-4516-a8f1-359c13f9fe8e

📥 Commits

Reviewing files that changed from the base of the PR and between 5735933 and bd4acf9.

📒 Files selected for processing (2)
  • pyre/pyre-interpreter/src/baseobjspace.rs
  • pyre/pyre-interpreter/src/jit_fnaddr.rs

Walkthrough

The change adds shared WTF-8 dictionary key helpers, extends MIR string identity handling to WTF-8 values, and registers runtime aliases for residualized helpers.

Changes

WTF-8 support

Layer / File(s) Summary
WTF-8 dictionary key helpers and dispatch
pyre/pyre-object/src/dictmultiobject.rs
Dictionary get and set paths use shared UTF-8 validation, unchecked &str conversion, and surrogate-key object construction.
MIR string identity folding
majit/majit-translate/src/front/mir.rs
Into identity handling recognizes String, str, Wtf8, and Wtf8Buf. wtf8_key_as_str_unchecked calls fold to their argument.
Residual runtime helper wiring
pyre/pyre-interpreter/src/baseobjspace.rs, pyre/pyre-interpreter/src/jit_fnaddr.rs
WTF-8 lookup and attribute-miss paths are residualized. JIT function-address aliases cover the required helpers.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DictionaryAccess
  participant Wtf8Helpers
  participant MIRTranslator
  participant JITRuntime
  DictionaryAccess->>Wtf8Helpers: validate and convert WTF-8 keys
  MIRTranslator->>MIRTranslator: fold string-family identity conversions
  MIRTranslator->>JITRuntime: resolve residual helper addresses
  JITRuntime-->>MIRTranslator: return registered function addresses
Loading

Possibly related PRs

Suggested reviewers: lifthrasiir

Poem

I’m a rabbit with keys in my sight,
WTF-8 paths now branch clean and bright.
Strings fold softly, helpers align,
Runtime addresses resolve on time.
Hop, hop—the dictionary is right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the PR's main changes: WTF-8 dictionary-key handling and type-lookup residual coverage.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rtyper-legacy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

🤖 Codex parity review

Static analysis of this diff vs the local RPython/PyPy sources (commit bd4acf9).
Updated: 2026-08-12T14:22:46.917Z

Files in the reviewed diff
majit/majit-translate/src/front/mir.rs
pyre/pyre-interpreter/src/baseobjspace.rs
pyre/pyre-interpreter/src/jit_fnaddr.rs
pyre/pyre-object/src/dictmultiobject.rs

1. Regressions to PyPy parity introduced by this patch

None.

2. Other mismatches introduced by this patch

  • majit/majit-translate/src/front/mir.rs:10649 and majit/majit-translate/src/front/mir.rs:12730rpython/rtyper/rstr.py:568: the new Wtf8/Wtf8Buf destination test aliases any T: Into<Wtf8Buf> call without proving T is string-valued or that the selected From<T> implementation is identity. RPython assigns string_repr only to SomeString; an arbitrary source value is not interchangeable with a string. A custom impl Into<Wtf8Buf> for T can transform its input, which this fold drops.

  • majit/majit-translate/src/front/mir.rs:12764rpython/rtyper/rstr.py:568: matching solely on the leaf name wtf8_key_as_str_unchecked folds any one-argument function of that name to its argument. There is no type, defining-module, or signature-result validation. A same-named non-identity function in any crate would be miscompiled.

3. Pre-existing mismatches (already present before this patch)

  • majit/majit-translate/src/front/mir.rs:12730rpython/rtyper/rstr.py:568: before this patch, the equivalent upstream/main code already folded every generic T: Into<String> call based only on the destination being String. As above, Into<String> may run an arbitrary From<T> conversion; only a proven string source / identity implementation can be aliased.

4. Structural adaptations

  • pyre/pyre-object/src/dictmultiobject.rs:3474 and pyre/pyre-object/src/dictmultiobject.rs:3531pypy/objspace/std/dictmultiobject.py:1092 and pypy/objspace/std/dictmultiobject.py:1220: the UTF-8-validity split plus WTF-8 surrogate slow path is a Python-version/compiler representation adaptation. PyPy receives a normal text key and directly wraps it with newtext; pyre must preserve lone surrogates carried by RustPython WTF-8 values.

  • pyre/pyre-interpreter/src/baseobjspace.rs:7344 and pyre/pyre-interpreter/src/baseobjspace.rs:9049rpython/rlib/jit.py:133: adding dont_look_inside residual boundaries for the attribute-miss and WTF-8 lookup projection has no line-for-line PyPy equivalent. It is a Rust translator/annotator containment adaptation; the functions retain their interpreter behavior.

  • pyre/pyre-interpreter/src/jit_fnaddr.rs:902 and pyre/pyre-interpreter/src/jit_fnaddr.rs:1079rpython/rlib/jit.py:133: registering Rust function addresses for those residual boundaries is required by majit’s generated-call mechanism and has no RPython source counterpart.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔇 Additional comments (4)
pyre/pyre-object/src/dictmultiobject.rs (1)

3436-3477: LGTM!

Also applies to: 3511-3514, 3531-3534

majit/majit-translate/src/front/mir.rs (1)

10598-10623: 🎯 Functional Correctness

⚠️ Unverified finding
Sandbox verification was unavailable.

Verify that every generic T bound by Into<Wtf8Buf>/Into<String> reaching this fold is string-representable.

trait_clause_into_string_identity and trait_into_string_alias both alias the destination directly to the call argument whenever dest_ty is string-family (tyref_is_string_value). Neither checks the source operand's type. The source is the unresolved generic T in the trait clause, so the check cannot see what concrete type flows in at any given call site sharing this generic body.

Widening the target check from "exact String ADT" to "any string-family destination" (including Wtf8/Wtf8Buf) enlarges the call-site population this identity fold applies to. If any type satisfying Into<Wtf8Buf> is not string-representable in the lifted value model (for example a byte-vector conversion), this fold would silently alias a real conversion to identity, producing a JIT-traced value that diverges from the interpreter.

As per coding guidelines, "The generated JIT must preserve the interpreter's semantics; never justify a mismatch by claiming Rust cannot be meta-traced. Fix deviations as generation defects." Please confirm no such source type exists for the call sites this fold now reaches.

Also applies to: 12678-12704

pyre/pyre-interpreter/src/baseobjspace.rs (1)

9034-9042: LGTM!

pyre/pyre-interpreter/src/jit_fnaddr.rs (1)

898-913: LGTM!

Also applies to: 1070-1084


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: da4a2b77-d73f-413d-93a3-d3fe91539c3f

📥 Commits

Reviewing files that changed from the base of the PR and between 56924a3 and 5735933.

📒 Files selected for processing (4)
  • majit/majit-translate/src/front/mir.rs
  • pyre/pyre-interpreter/src/baseobjspace.rs
  • pyre/pyre-interpreter/src/jit_fnaddr.rs
  • pyre/pyre-object/src/dictmultiobject.rs

Mark `object_getattr_miss` `#[dont_look_inside]` and register it in
`jit_fnaddr`. It is the miss / special-attribute path of `getattribute`,
reached only after the fast descriptor and instance-dict lookups return
nothing. Its `[Option<PyObjectRef>; 2].iter().flatten()` metaclass walks
and array indexing are opaque to the annotator; it returns the blessed
`PyResult` carrier, so the whole cold path residualises behind one
boundary.

The prepass census `Flatten::next` fallback clears; the getattr graphs
relocate to their next wall rather than lifting (0 lift).

Assisted-by: Claude

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

https://github.com/youknowone/pyre/blob/bd4acf94387ca4a20a1ace5bdb738a1a22e9f60b/pyre-interpreter/src/jit_fnaddr.rs#L906
P1 Badge Register word-ABI trampolines for WTF-8 residuals

On wasm32, when a compiled trace reaches a WTF-8 dict adapter, this registers the raw Rust fn(&Wtf8) -> bool, whose WebAssembly type is (i32) -> i32, while residual call_indirect descriptors use the uniform (i64) -> i64 word ABI; jit_fnaddr.rs:1106-1109 and :2103-2110 document that this mismatch traps at runtime. The sibling surrogate helper registered at line 912 has the same reference-argument problem. Expose/register word-ABI trampolines rather than these raw pointers.

AGENTS.md reference: AGENTS.md:L14-L19


https://github.com/youknowone/pyre/blob/bd4acf94387ca4a20a1ace5bdb738a1a22e9f60b/pyre-interpreter/src/baseobjspace.rs#L7344
P2 Badge Keep the hot __getattr__ path traceable

When a loop repeatedly reads a missing instance or metaclass attribute, this annotation residualizes the entire dispatcher, including the get_and_call_function invocation of user __getattr__, so each iteration exits the parent trace instead of inlining the lookup and callback. This path is demonstrably hot in pyre/bench/synth/metaclass_getattr.py:24-32, while PyPy performs the corresponding hook call in the undecorated _handle_getattribute path (pypy/objspace/descroperation.py:234-245); isolate the unsupported projection/array operation rather than black-boxing the dispatcher.

AGENTS.md reference: AGENTS.md:L231-L233

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@youknowone
youknowone merged commit e78cf29 into main Aug 12, 2026
17 checks passed
@youknowone
youknowone deleted the rtyper-legacy branch August 12, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant